#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <curl/curl.h>
#include "config.h"
#include "comm.h"
#include "main.h"
#include "lb.h"
#include "dist_url_client.h"

struct curl_handle {
	CURL *curl;
	struct curl_slist *slist;
	struct memory *header;
	struct memory *content;
	FILE *fp;
};

struct memory {
	char *data;
	int size;
};

void *crawl_thread(void *arg)
{
	time_t load_time = 0;
	CONF conf_pri;
	CURLM *curlm_handle;
	char *urls = NULL;
	unsigned *servs = NULL;
	int selected_serv;
	int cur_url_num = 0;
	char url_buf[1024];

	curlm_handle = curl_multi_init();

	while (1) {
		pthread_rwlock_rdlock(&conf_lock);
		if (conf.cmd == CONF_QUIT) {
			pthread_rwlock_unlock(&conf_lock);
			break;
		}
		if (load_time != conf.init_time) {
			destroy_conf(&conf_pri);
			conf_cpy(&conf_pri, &conf);
			load_time = conf.init_time;
			if (servs)
				free(servs);
			servs = (unsigned *)malloc(sizeof(unsigned) * conf_pri.url_server_num);
			memset(servs, 0, sizeof(unsigned) * conf_pri.url_server_num);
		}
		if (!conf_pri.regular[0]) {
			pthread_rwlock_unlock(&conf_lock);
			sleep(1);
			continue;
		}
		pthread_rwlock_unlock(&conf_lock);
		/*
		 * 对URL分发服务进行负载均衡
		 * */
		selected_serv = lb(NULL, conf_pri.url_server_num, servs, RRS);

		/*
		 * 从负载均衡后的URL分发服务器处获取到的URL
		 * 应在管理线程中添加获取URL的正则表达式
		 * */
		urls = get_urls(&conf_pri.url_server[selected_serv].ip, conf_pri.url_server[selected_serv].port, 0, conf_pri.per_thread_uris - cur_url_num, conf_pri.regular);
		if (!urls) {
			printf("ger_urls failed\n");
			//loggggggggggggggggg
			sleep(1);
			continue;
		}
		char *start = urls;
		char *p = NULL;
		p = strchr(start, '\n');
		while (p) {
			*p = '\0';
			//////////////////
			//use start
			//get_host_from_url
			//////////////////
			//if (get_host_from_url(start, url_buf) == 0) {
			//}
			start = p + 1;
			p = strchr(start, '\n');
		}
	}
	return (void *)1;
}

static size_t write_header(void *ptr, size_t size, size_t nmemb, void *stream)
{
	size_t malloc_s = size * nmemb;
	struct memory *header = (struct memory *)stream;
	if (header->size != malloc_s)
		header->data = (char *)realloc(header->data, malloc_s);
	header->size = malloc_s;
	memcpy(header->data, ptr, malloc_s);
	return malloc_s;
}

/*
 * 在每个URL返回时需要将stream清0
 * */
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
	size_t realsize = size * nmemb;
	struct memory *mem = (struct memory *)stream;
	
	mem->data = (char *)realloc(mem->data, mem->size * realsize);
	memcpy(&(mem->data[mem->size]), ptr, realsize);
	mem->size += realsize;
	return realsize;
}

static void destroy_curl_handle(struct curl_handle *h)
{
	if (h) {
		if (h->header) {
			if (h->header->data)
				free(h->header->data);
			free(h->header);
		}
		if (h->content) {
			if (h->content->data) 
				free(h->content->data);
			free(h->content);
		}
		if (h->slist)
			curl_slist_free_all(h->slist);
		if (h->curl)
			curl_easy_cleanup(h->curl);
		if (h->fp)
			fclose(h->fp);
		free(h);
	}
}

static struct curl_handle *init_easy_curl(const CONF *conf_pri, const char *url)
{
	CURL *curl = curl_easy_init();
	if (!curl)
		return NULL;
	struct curl_slist *slist = NULL;
	char buf[4096];

	for (int i = 0; i < conf_pri->req_header.attr_num; i++) {
		buf[0] = '\0';
		strcat(buf, conf_pri->req_header.attr[i].attr_name);
		strcat(buf, ": ");
		strcat(buf, conf_pri->req_header.attr[i].attr_value);
		slist = curl_slist_append(slist, buf);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
	}
	curl_easy_setopt(curl, CURLOPT_ENCODING, "");
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
	struct memory *header = (struct memory *)malloc(sizeof(struct memory));
	struct memory *content = (struct memory *)malloc(sizeof(struct memory));
	memset(header, 0, sizeof(struct memory));
	memset(content, 0, sizeof(struct memory));
	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_header);
	curl_easy_setopt(curl, CURLOPT_WRITEHEADER, header);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, content);
	curl_easy_setopt(curl, CURLOPT_MAXREDIRS, -1);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
	if (strcmp(conf_pri->req_header.method, "GET") == 0)
		curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
	else if (strcmp(conf_pri->req_header.method, "GET") == 0)
		curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(curl, CURLOPT_URL, url);
	struct curl_handle *handle = (struct curl_handle *)malloc(sizeof(struct curl_handle));
	handle->curl = curl;
	handle->slist = slist;
	handle->header = header;
	handle->content = content;
	char *p = strdup(conf_pri->file_temp);
	int fd = mkstemp(p);
	if (fd < 0)
		handle->fp = NULL;
	else
		handle->fp = fdopen(fd, "a");
	free(p);
	return handle;
}
